package com.hong.atomic;

import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Auther: Administrator
 * @Date: 2018/7/20 18:02
 * @Description:
 */
public class UnsafeTest {
    /**
     *
     * @param args
     */
    public static void main(String[] args) throws Exception {
       /* Unsafe unsafe = Unsafe.getUnsafe();
        System.out.println(unsafe);*/
        /*Unsafe unsafe = getUnsafe();
        System.out.println(unsafe);*/

        /**
         * stupiedCounter
         * Counter result
         */

        ExecutorService service = Executors.newFixedThreadPool(1000);
        Counter counter = new CasCounter();
        long start = System.currentTimeMillis();
        for (int i=0;i<1000;i++){
            service.submit(new CounterRunnable(counter,10000));
        }
        service.shutdown();
        service.awaitTermination(1,TimeUnit.HOURS);
        long end = System.currentTimeMillis();
        System.out.println("counter result:"+counter.getCounter());
        System.out.println("Time passed in ms :"+(end-start));

    }

    private static Unsafe getUnsafe(){
        try {
            Field f = Unsafe.class.getDeclaredField("theUnsafe");
            f.setAccessible(true);
            return  (Unsafe)f.get(null);
        } catch (Exception e) {
            throw  new RuntimeException(e);
        }
    }

    interface Counter{
        void increment();
        long getCounter();
    }

    static class StupiedCounter implements Counter{

        private long counter = 0;


        public void increment() {
            counter++;
        }

        public long getCounter() {
            return counter;
        }
    }

    static class LockCounter implements Counter{

        private long counter = 0;

        private final Lock lock =new ReentrantLock();

        public void increment() {
            counter++;
        }

        public long getCounter() {
            return counter;
        }
    }
    static class AtomicCounter implements Counter{

        private AtomicLong counter = new AtomicLong();


        public void increment() {
            counter.incrementAndGet();
        }

        public long getCounter() {
            return counter.get();
        }
    }

    static class CasCounter implements Counter{

        private volatile long counter = 0;
        private Unsafe unsafe;
        private long offset;

        public CasCounter() throws Exception {
            unsafe = getUnsafe();
            offset = unsafe.objectFieldOffset(CasCounter.class.getDeclaredField("counter"));
        }

        public void increment() {
            long cunrrent = counter;
            while (!unsafe.compareAndSwapLong(this,offset,cunrrent,cunrrent+1)){
                cunrrent = counter;
            }
        }

        public long getCounter() {
            return counter;
        }
    }

    static class CounterRunnable implements Runnable{

        private final  Counter counter;

        private final  int num;

        public CounterRunnable(Counter counter, int num) {
            this.counter = counter;
            this.num = num;
        }

        public void run() {
            for (int i =0;i<num;i++){
                counter.increment();
            }
        }
    }
}
